package com.lagou.sqlSession;

import com.lagou.configuration.BoundSql;
import com.lagou.pojo.Configuration;
import com.lagou.pojo.MappedStatement;
import com.lagou.utils.GenericTokenParser;
import com.lagou.utils.ParameterMapping;
import com.lagou.utils.ParameterMappingTokenHandler;
import com.mysql.jdbc.StringUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

/**
 * @author dcwu5
 * @date 2020-05-23
 * @description
 */
public class SimpleExcutor implements Excutor {
    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) {
        try {
            //1、注册驱动获取连接
            Connection connection = configuration.getDataSource().getConnection();
            //2、获取sql 带？
            String sql = mappedStatement.getSql();
            BoundSql boundSql = getBoundSql(sql);
            // 3、获取预处理对象
            PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
            // 4、设置参数
            String parameterType = mappedStatement.getParameterType();
            Class<?> classParameter = getClassType(parameterType);
            List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
            for (int i = 0; i < parameterMappingList.size(); i++) {
                // 获取参数名
                String content = parameterMappingList.get(i).getContent();
                // 反射
                Field declaredField = classParameter.getDeclaredField(content);
                // 暴力访问
                declaredField.setAccessible(true);
                Object o = declaredField.get(params[0]);
                // 设置参数
                preparedStatement.setObject(i + 1, o);
            }
            // 5、执行sql
            ResultSet resultSet = preparedStatement.executeQuery();
            String resultType = mappedStatement.getResultType();
            Class<?> classType = getClassType(resultType);

            List<Object> objectList = new ArrayList<>();
            // 6、返回结果集
            while (resultSet.next()) {
                Object o = classType.newInstance();
                // 元数据
                ResultSetMetaData metaData = resultSet.getMetaData();
                for (int i = 0; i < metaData.getColumnCount(); i++) {
                    // 字段名
                    String columnName = metaData.getColumnName(i + 1);
                    // 字段值
                    Object value = resultSet.getObject(columnName);

                    // 通过反射或内省完成字段封装
                    PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, classType);
                    Method writeMethod = propertyDescriptor.getWriteMethod();
                    writeMethod.invoke(o, value);

                }
                objectList.add(o);
            }
            return (List<E>) objectList;


        } catch (Exception throwables) {
            throwables.printStackTrace();
        }

        return null;
    }

    // 获取class对象
    private Class<?> getClassType(String parameterType) throws ClassNotFoundException {
        if (!StringUtils.isNullOrEmpty(parameterType)) {
            Class<?> aClass = Class.forName(parameterType);
            return aClass;
        } else {
            return null;
        }


    }

    private BoundSql getBoundSql(String sql) {
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
        // 解析过有？占位符的sql
        String parse = genericTokenParser.parse(sql);
        // 参数list
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        BoundSql boundSql = new BoundSql();
        boundSql.setParameterMappingList(parameterMappings);
        boundSql.setSqlText(parse);
        return boundSql;
    }


    @Override
    public int update(Configuration configuration, MappedStatement mappedStatement, Object[] params) {
        try {
            //1、注册驱动获取连接
            Connection connection = configuration.getDataSource().getConnection();
            //2、获取sql 带？
            String sql = mappedStatement.getSql();
            BoundSql boundSql = getBoundSql(sql);
            // 3、获取预处理对象
            PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
            // 4、设置参数
            String parameterType = mappedStatement.getParameterType();
            Class<?> classParameter = getClassType(parameterType);
            List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
            for (int i = 0; i < parameterMappingList.size(); i++) {
                // 获取参数名
                String content = parameterMappingList.get(i).getContent();
                // 反射
                Field declaredField = classParameter.getDeclaredField(content);
                // 暴力访问
                declaredField.setAccessible(true);
                Object o = declaredField.get(params[0]);
                // 设置参数
                preparedStatement.setObject(i + 1, o);
            }
            // 5、执行sql
            int i1 = preparedStatement.executeUpdate();
            return i1;


        } catch (Exception throwables) {
            throwables.printStackTrace();
        }
        return 0;
    }
}
